package com.xzz.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.xzz.domain.*;
import com.xzz.constants.VerifyCodeConstants;
import com.xzz.dto.RedisRegisterDto;
import com.xzz.dto.RegisterDto;
import com.xzz.enums.GlobalErrorCode;
import com.xzz.feign.LoginFeignClient;
import com.xzz.mapper.UserMapper;
import com.xzz.result.JSONResult;
import com.xzz.service.IUserAccountService;
import com.xzz.service.IUserBaseInfoService;
import com.xzz.service.IUserCodeService;
import com.xzz.service.IUserService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.xzz.util.AssertUtil;
import com.xzz.util.BitStatesUtils;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author xzz
 * @since 2022-08-26
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private LoginFeignClient loginFeignClient;

    @Autowired
    private IUserAccountService userAccountService;

    @Autowired
    private IUserBaseInfoService userBaseInfoService;

    @Autowired
    private IUserCodeService userCodeService;

    @Override
    @GlobalTransactional
    public void smsRegister(RegisterDto smsRegisterDto) {
        String mobile = smsRegisterDto.getMobile();
        Integer regChannel = smsRegisterDto.getRegChannel();
        String password = smsRegisterDto.getPassword();
        String smsCode = smsRegisterDto.getSmsCode();

        //303校验

        // 2.验证码在Redis中是否过期/存在
        String key = String.format(VerifyCodeConstants.REGISTER_CODE_PREFIX, mobile);
        Object codeObj = redisTemplate.opsForValue().get(key);
        // 2.1.校验验证码是否存在，如果不存在那么说明已过期
        AssertUtil.isNotNull(codeObj, GlobalErrorCode.CODE_EXPIRED_ERROR);
        // 2.2.校验验证码是否正确
        RedisRegisterDto codeDto = (RedisRegisterDto) codeObj;
        AssertUtil.isEqualsIgnoreCase(codeDto.getCode(), smsCode, GlobalErrorCode.CODE_MISMATCH_ERROR);

        //3.手机号是否被注册过了，如果已经存在那么抛出异常
        User user = selectByPhone(mobile);
        AssertUtil.isNull(user, GlobalErrorCode.USER_EXIST_ERROR);

        //4.保存t_login，使用uaaFeign
        JSONResult saveLogin = saveLogin(smsRegisterDto);
        AssertUtil.isTrue(saveLogin.isSuccess(), GlobalErrorCode.SERVICE_ERROR);//判断服务方是否熔断
        Long loginId = Long.valueOf(saveLogin.getData().toString());
        AssertUtil.isNotNull(loginId, GlobalErrorCode.USER_LOGIN_ERROR);//判断是否保存成功

        //5.保存t_user
        User saveUser = saveUser(loginId,smsRegisterDto);
        AssertUtil.isNotNull(saveUser.getId(), GlobalErrorCode.USER_LOGIN_ERROR);//判断是否保存成功

        //5.1 保存t_user_account
        initUserAccount(saveUser.getId());

        //5.2 保存t_user_base_info
        initUserBaseInfo(saveUser.getId(), smsRegisterDto);

        //扩展：保存推荐码
        userCodeService.adduserCode(saveUser.getId());
    }

    //根据电话查询用户
    private User selectByPhone(String mobile) {
        // 1.创建Wrapper条件构造器器
        Wrapper<User> wrapper = new EntityWrapper<>();
        // 2.传入sql条件，"phone"数据库字段，mobile自己封装的字段，eq为相等
        wrapper.eq("phone", mobile);
        return selectOne(wrapper);
    }

    //保存login
    private JSONResult saveLogin(RegisterDto smsRegisterDto) {
        Login login = new Login();
        login.setUsername(smsRegisterDto.getMobile());
        login.setPassword(smsRegisterDto.getPassword());
        login.setType(1);
        login.setEnabled(true);
        return loginFeignClient.saveOrUpdate(login);
    }

    //保存用户信息
    private User saveUser(Long loginId, RegisterDto smsRegisterDto) {
        User user = new User();
        user.setLoginId(loginId);
        user.setCreateTime(new Date().getTime());
        user.setPhone(smsRegisterDto.getMobile());
        user.setNickName(smsRegisterDto.getMobile());

        //安全等级设置
        long bitState = BitStatesUtils.addState(BitStatesUtils.OP_REGISTED, BitStatesUtils.OP_ACTIVED);//注册成功+激活成功
        bitState = BitStatesUtils.addState(bitState, BitStatesUtils.OP_AUTHED_PHONE);//已有状态+手机认证
        user.setBitState(bitState);// 设置用户初始为状态值

        //添加推荐人id
        UserCode userCode = userCodeService.findByCode(smsRegisterDto.getCode());
        user.setThirdUid(String.valueOf(userCode.getUserId()));

        insert(user);//本身就在userservice里面写的代码，同一个类调方法，不需要注入
        return user;
    }

    //初始化用户账户信息
    private void initUserAccount(Long userId) {
        UserAccount userAccount = new UserAccount();
        userAccount.setId(userId);
        userAccount.setCreateTime(new Date().getTime());
        // 此处成功发送邮件告知用户初始支付密码
        userAccount.setPassword("123456");
        userAccountService.insert(userAccount);
    }

    //初始化用户基本信息
    private void initUserBaseInfo(Long userId, RegisterDto smsRegisterDto) {
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setId(userId);
        userBaseInfo.setCreateTime(new Date().getTime());
        userBaseInfo.setRegChannel(smsRegisterDto.getRegChannel());
        userBaseInfoService.insert(userBaseInfo);
    }

    //通过推荐码查询user
    @Override
    public User getUser(String code) {
        EntityWrapper<User> wrapper = new EntityWrapper<>();
        wrapper.eq("code", code);
        User user = selectOne(wrapper);
        return user;
    }

}
